
#include "CH58x_common.h"
#include <stdarg.h>
#include "zqm_global.h"


// ##全局变量 ------------------------------------------------------------------------------------
unsigned long long zq_last_tick = 0;                // 辅助计时器计算用。其他地方不要用。注：上电计时用SysTick->CNT, 系统tick计数器，单位 1/60000 ms。
volatile unsigned int zq_timer_50ms = 0;            // 主任务循环前开始计时, 50ms精度, 单位1ms, 基于高速时钟。主循环前会清零, 约49天多会溢出, 溢出后跳过0重新由TASK_PERIOD开始, 可以用来=0判断初始化。是大部分系统上电（规格书定义真正上电开始是自检后）计时的依据，不能用于长期累加计时.
volatile unsigned int zq_timer_s;			        // 主任务循环前开始计时, 1s精度, 基于高速时钟。主循环前会清零,
volatile unsigned int zq_timer_rtc_s;			    // 上电初始化计时器开始计时(唤醒后不会清零), 单位1s, 基于内部RC低速时钟。用于1. 休眠24小时唤醒计时, 2. 系统总运行时间
volatile unsigned int zq_timer_rtc_s_pow;			// 上电初始化计时器开始计时(唤醒后会清零, 只有normal模式使用, 自检后清零开始计数), 单位1s, 基于内部RC低速时钟。用于1. 判断上电(首次和唤醒)
volatile unsigned int zq_rtc_wdt_10s;		        // 休眠时候WDG基于高速系统时钟，无法使用，使用RTC定时器模拟一个10s的watchdog
ZqMcuStates zy_st = { 0 };                          // 系统状态


// 系列原子操作函数: 1. *addr = 0;
void AtomicClear32(volatile uint32_t *addr)
{
#if(!ZQ_SIMULATOR)
    uint32_t result;
    __asm volatile ("amoswap.w %0, %2, %1" : "=r"(result), "+A"(*addr) : "r"(0) : "memory");
#else
    *addr = 0;
#endif
}
// 系列原子操作函数: 2. *addr ^= val;
void AtomicXor32(volatile uint32_t *addr, uint32_t val)
{
#if(!ZQ_SIMULATOR)
    uint32_t result;
    __asm volatile ("amoxor.w %0, %2, %1" : "=r"(result), "+A"(*addr) : "r"(val) : "memory");
#else
    *addr ^= val;
#endif
}
// 系列GPIOA/B操作函数
void GPIO_ModeCfg(uint32_t gpio, GPIOModeTypeDef mode)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) GPIOA_ModeCfg(io, mode);
    else GPIOB_ModeCfg(io, mode);
}
void GPIO_ResetBits(uint32_t gpio)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) GPIOA_ResetBits(io);
    else GPIOB_ResetBits(io);
}
void GPIO_SetBits(uint32_t gpio)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) GPIOA_SetBits(io);
    else GPIOB_SetBits(io);
}
void GPIO_InverseBits(uint32_t gpio)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) GPIOA_InverseBits(io);
    else GPIOB_InverseBits(io);
}
uint32_t GPIO_ReadPortPin(uint32_t gpio)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return 0;		// TODO 读取不存在的IO，返回0
    else if (io == gpio) return GPIOA_ReadPortPin(io);
    else return GPIOB_ReadPortPin(io);
}
void GPIO_ITModeCfg(uint32_t gpio, GPIOITModeTpDef mode)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) GPIOA_ITModeCfg(io, mode);
    else GPIOB_ITModeCfg(io, mode);
}
void GPIO_EnableIRQ(uint32_t gpio, bool en)
{
	uint32_t io = gpio & ZyGPIO_MASK;
	if(io == 0)	return;
    else if (io == gpio) {en ? (R16_PA_INT_EN |= io) : (R16_PA_INT_EN &= (~io));}
    else {en ? (R16_PB_INT_EN |= io) : (R16_PB_INT_EN &= (~io));}
}

#define ZQ_MSG_QUEUE_LEN	20
typedef struct {
	int cnt;			// 实际有多少条记录
	int pos;			// 指向下一个写入记录存放位置
	ZqMessage msgs[ZQ_MSG_QUEUE_LEN];		// Circular Stack 记录数组地址
} ZqMsgQueue;

static ZqMsgQueue zqMsgQueue;

// int zq_StackInit(zq_CircularStack *pStack, int Count, int RecSize)
void ZqInitMsgQueue(void)
{
	zqMsgQueue.cnt = 0;
	zqMsgQueue.pos = 0;
}
void zqPostMessage(ZqMessage msg)
{
	zqMsgQueue.msgs[zqMsgQueue.pos] = msg;
	zqMsgQueue.cnt = (zqMsgQueue.cnt < ZQ_MSG_QUEUE_LEN) ? (zqMsgQueue.cnt + 1) : ZQ_MSG_QUEUE_LEN;
	zqMsgQueue.pos = (zqMsgQueue.pos < (ZQ_MSG_QUEUE_LEN - 1)) ? (zqMsgQueue.pos + 1) : 0;
}
int ZqGetMessage(ZqMessage *pmsg)
{
	if(zqMsgQueue.cnt == 0) {
		pmsg->id = 0;
		return pmsg->id;
	}
	int pos = zqMsgQueue.pos - zqMsgQueue.cnt;
	if (pos < 0) pos += ZQ_MSG_QUEUE_LEN;
	pmsg->id = zqMsgQueue.msgs[pos].id;
	pmsg->param1 = zqMsgQueue.msgs[pos].param1;
	pmsg->param2 = zqMsgQueue.msgs[pos].param2;
	--zqMsgQueue.cnt;
	return pmsg->id;
}

// 10位数四舍五入：比如 113 --> 110
int round_10(int num)
{
	num = (num >= 0) ? (num + 5) : (num - 5);
	return (num / 10) * 10;
}

__HIGH_CODE
short ZyAverageShort(short *pv, uint8_t n)
{
    int sum = 0;
    short max = 0, min = 0x7fff;
    
    short *pe = pv + n;
    for(; pv < pe; pv++) {
        sum += *pv;
        if (min > *pv) min = *pv;
        if (max < *pv) max = *pv;
    }
    return (short)((n < 3) ? (sum / n) : ((sum - min - max) / (n - 2)));
}
// 支持长时间的延迟
void M0DelayMs(int ms)
{
	int i = 50;
	for(; i < ms; i+=50) {
		DelayMs(50);
		WdtClean();
		DbgTask();
	}
	DelayMs(50 - (i - ms));
	WdtClean();
	DbgTask();
}

// create a ring buffer
ZqRingBuf *ZqRingBufCreate(uint8_t *org_buf, int len)
{
	if(org_buf == NULL || len < sizeof(ZqRingBuf))
		return NULL;
	ZqRingBuf * prb = (ZqRingBuf *)org_buf;
	prb->size = len - sizeof(ZqRingBuf);
	prb->r_pos = prb->len = 0;
	return prb;
}
int ZqRingBufSize(ZqRingBuf *prb)
{
	return prb->size;
}
int ZqRingBufDateSize(ZqRingBuf *prb)
{
	return prb->len;
}

void ZqRingBufFlush(ZqRingBuf* prb, int len)
{
	if(len > prb->len) len = prb->len;

	int x = (prb->r_pos + len) - prb->size;
	if(x >= 0)  // loop
		prb->r_pos = 0;
	else 
		x = len;
	prb->r_pos += x;
	prb->len -= len;
	return;
}

__HIGH_CODE
int ZqRingBufWrite(ZqRingBuf *prb, const uint8_t *buf, int len)
{
	if(len > (prb->size - prb->len))  // overflow
		return 0;

	int w_pos = (prb->r_pos + prb->len) % prb->size;
	int x = (w_pos + len) - prb->size;
	if(x >= 0) { // loop
		int y = len - x;
		memcpy(prb->data + w_pos, buf, y);
		w_pos = 0;
		buf += y;
	}
	else 
		x = len;
	memcpy(prb->data + w_pos, buf, x);
	prb->len += len;
	return len;
}

__HIGH_CODE
int ZqRingBufTryRead(ZqRingBuf *prb, uint8_t *buf, int len)
{
	if(len > prb->len) len = prb->len;

	int r_pos = prb->r_pos;
	int x = (r_pos + len) - prb->size;
	if(x >= 0) { // loop
		int y = len - x;
		memcpy(buf, prb->data + r_pos, y);
		r_pos = 0;
		buf += y;
	}
	else 
		x = len;
	memcpy(buf, prb->data + r_pos, x);
	return len;
}

__HIGH_CODE
int ZqRingBufRead(ZqRingBuf *prb, uint8_t *buf, int len)
{
	len = ZqRingBufTryRead(prb, buf, len);
	prb->r_pos = (prb->r_pos + len) % prb->size;
	prb->len -= len;
	return len;
}


// Calibrate system time
static int zqm_time_cali = 0;
uint32_t ZqmGetSysTimestamp(void)
{
    // 获取当前时间的年、月、日、时、分、秒
    uint16_t year, mon, day, hour, min, sec;
	RTC_GetTime(&year, &mon, &day, &hour, &min, &sec);
	uint32_t timestamp = ZqDateToTimestamp(year, mon, day, hour, min, sec);
	timestamp = (zqm_time_cali >= 0) ? (timestamp + zqm_time_cali) : (timestamp - (uint32_t)(-zqm_time_cali));
	return timestamp;
}
void ZqmGetSysTime(uint16_t *py, uint16_t *pmon, uint16_t *pd, uint16_t *ph, uint16_t *pm, uint16_t *ps)
{
	uint32_t timestamp = ZqmGetSysTimestamp();
	ZqTimestampToDate(timestamp, py, pmon, pd, ph, pm, ps);
	return;
}
bool ZqmCaliSysTime(uint32_t new_stamp)
{
    // 获取当前时间的年、月、日、时、分、秒
	uint32_t timestamp = ZqmGetSysTimestamp();
	int diff = (new_stamp >= timestamp) ? (int)(new_stamp - timestamp) : -(int)(timestamp - new_stamp);
	if(diff > 30 || diff < -30) { // 30s以内不校正
		zqm_time_cali = diff;
		return true;
	}
	return false;
}

